Creating custom controls

A key element in building interactions with Kanzi is the use of UI components, which implement interactivity in the user interfaces. However, when you have to use a very specific need for creating user interaction you can either define a custom implementation of an existing control in the application implementation or you can create a custom control you can load as a static .lib library and use in your Kanzi application. The advantages of creating a custom control are mostly in reusability. Using a tool module, you can make the custom control, its logic, properties, and messages available directly in Kanzi Studio.

Examine the Custom_component example to see how custom controls are implemented. The example includes a Custom_component_toolmodule configuration, which you can use to generate a toolmodule plugin (.dll). By adding this preview module into your application configuration in Kanzi Studio, you can see the behavior of your custom control in the Preview. Kanzi Studio also imports all properties and message types that are defined in the registerToFactory implementation, so you can use them in Kanzi Studio similarly to any other components and message types.

To create a custom control:

  1. Create a custom control project. For example, use the Custom_component example as a base. See Custom component example.
  2. Define an object type identifier for your custom control.
    const KzuFactoryObjectTypeIdentifier = OBJECT_TYPE_MYCONTROL
  3. Provide an implementation of KzuUiComponentNodeClass for your custom control. Often, implementing your custom initialize and uninitialize functions is sufficient and you can use the default implementations for everything else.
    const struct KzuUiComponentNodeClass CUSTOM_MYCONTROL_CLASS =
    {
        {
            &KZU_UI_COMPONENT_NODE_CLASS,
            myControlInitialize,
            myControlUninitialize,
            kzuObjectNodeOnAttached_protected,
            kzuObjectNodeOnDetached_protected,
            kzuUiComponentNodeCopy_protected,
            kzuUiComponentNodeRender_protected,
            kzuUiComponentNodeGetBoundingVolume_protected
        },
        kzuUiComponentNodeMeasure_protected,
        kzuUiComponentNodeArrange_protected,
        kzuUiComponentNodeValidateRender_protected,
        kzuUiComponentNodeCopyComponent_protected
    };
    
  4. Implement any input manipulators and message handlers specific to your custom control to define the component’s behavior. Manage creation and deletion of the components at myControlInitialize and myControlUninitialize. Override OnAttached and OnDetached instead, if the logic is dependent on the object’s existence in the scene graph hierarchy.
  5. Implement a registerToFactory function, which registers the object type FACTORY_OBJECT_TYPE_MYCONTROL, as well as any custom properties and message types that are generated or used by the control.
  6. Build a static .lib library, from your custom control implementation and include it in the project where you want to use the custom control.
  7. Register the custom control component in your application by calling the defined registerToFactory implementation in your application’s kzApplicationConfigure implementation.

The following code shows simple initialize and uninitialized behavior where the custom control only registers and deregisters a message handler for a custom message type:

KZ_CALLBACK static kzsError myControlInitialize(struct KzuObjectNode* objectNode)
{
    struct KzuUiComponentNode* componentNode = 
        kzuUiComponentNodeFromObjectNode(objectNode);
    struct MyControl* myControl = 
        myControlFromUiComponentNode(componentNode);
    struct KzuMessageDispatcher* messageDispatcher = 
        kzuObjectNodeGetMessageDispatcher(objectNode);

    /* Initialize parent class. */
    kzuUiComponentNodeInitialize_private(objectNode);

    /* Add a message handler for myCustomMessages for the myControl object node. We 
     * define object-source as KZ_NULL, so that all myCustomMessages that originate 
     * from myControl's children will be intercepted. */
    kzuMessageDispatcherAddHandler(messageDispatcher, objectNode, 
        MESSAGE_MY_CUSTOM_MESSAGE, KZ_NULL, myCustomMessageHandler, myControl);
 
    kzsSuccess();
}
KZ_CALLBACK static kzsError myControlUninitialize(struct KzuObjectNode* objectNode)
{
    struct KzuUiComponentNode* componentNode = 
        kzuUiComponentNodeFromObjectNode(objectNode);
    struct MyControl* myControl = 
        myControlFromUiComponentNode(componentNode);
    struct KzuMessageDispatcher* messageDispatcher =
        kzuObjectNodeGetMessageDispatcher(objectNode);
 
    /* Remove the message handler that was created for the custom component. */
    kzuMessageDispatcherRemoveHandler(messageDispatcher, objectNode, 
        MESSAGE_MY_CUSTOM_MESSAGE, myCustomMessageHandler, myControl);

    /* Uninitialize parent class. */
    kzuUiComponentNodeUninitialize_private(objectNode);
 
    kzsSuccess();
}